package imgcompress

import (
	"bytes"
	"context"
	"fmt"
	"net/http"
	"strings"

	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/config"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/helper"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/kycadminapi"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/utils"
	"git.bybit.com/svc/go/pkg/bzap"
	"go.uber.org/zap"
	"gopkg.in/gographics/imagick.v3/imagick"
)

type ImgCps = *imgCompress

type imgCompress struct {
	logger *zap.Logger
	teller kycadminapi.Teller
}

func New(
	logger *zap.Logger,
	teller kycadminapi.Teller,
) ImgCps {
	return &imgCompress{
		logger: logger,
		teller: teller,
	}
}

const (
	FilterType imagick.FilterType = imagick.FILTER_LANCZOS2
)

func (i *imgCompress) CompressImg(ctx context.Context, imgRaw []byte) ([]byte, error) {
	var (
		err     error
		srcSize int
		cpsRaw  []byte
	)
	srcSize = len(imgRaw)
	defer func() {
		if err != nil {
			bzap.LogError(i.logger, fmt.Sprintf("CompressImg %d Byte", srcSize), err)
			_ = i.teller.KycAlarm(ctx, "CompressImg", err)
		}
	}()
	defer helper.TimeCost(i.logger, "CompressImg")()

	cfg := config.GetImageCompressConfig()
	srcKB := srcSize / (1 << 10)
	// 最小大小限制
	if srcKB < cfg.MinSize {
		i.logger.Info("CompressImg less than min size", zap.Int("before", srcKB))
		return imgRaw, nil
	}

	// 忽略 pdf 文件
	mime := http.DetectContentType(imgRaw)
	if strings.Contains(mime, "/pdf") || utils.IsValidPDF(bytes.NewReader(imgRaw)) {
		i.logger.Info("CompressImg ignore pdf", zap.Int("before", srcKB))
		return imgRaw, nil
	}

	// 创建新的MagicWand
	mw := imagick.NewMagickWand()
	defer mw.Destroy()
	// 读取文件
	err = mw.ReadImageBlob(imgRaw)
	if err != nil {
		return nil, err
	}
	// 得到并重设图片大小
	width := mw.GetImageWidth()
	height := mw.GetImageHeight()
	err = mw.ResizeImage(width, height, FilterType)
	if err != nil {
		return nil, err
	}
	// 改变图片质量
	err = mw.SetImageCompressionQuality(cfg.Quality)
	if err != nil {
		return nil, err
	}
	// 导出图片
	err = mw.SetImageFormat(cfg.Format)
	if err != nil {
		return nil, err
	}
	cpsRaw = mw.GetImageBlob()
	dstKB := len(cpsRaw) / (1 << 10)
	i.logger.Info("CompressImg",
		zap.String("before", fmt.Sprintf("%dK", srcKB)),
		zap.String("after", fmt.Sprintf("%dK", dstKB)),
		zap.String("reduce", fmt.Sprintf("%dK", srcKB-dstKB)))

	return cpsRaw, nil
}
